from models.gamedata import *
from models.gamelog import GameFlowLogEntry, timestamp
from google.appengine.runtime import apiproxy_errors

import copy
import logging

class GameFlowException(GameException):
    """Class used to create Game Flow Specific Exceptions"""
    def __init__(self, code=None, message=None):
            self.code=code or -34000
            self.message=message or "GameFlow Error"

class GameFlowCache(object):    
    _objects={}
    _new_objects=[]
    
    @classmethod
    def get(cls, o):
        if (o==None):
            return None
        elif isinstance(o, db.Key):
            if o in cls._objects.keys():
                return cls._objects[o]
            else:
                return db.get(o)
            
        elif isinstance(o, db.Model):
            if o.key() in cls._objects.keys():
                return cls._objects[o.key()]
            else:
                return o
        else:
            raise TypeError
        
    @classmethod
    def add(cls, o):
        if not isinstance(o, db.Model):
            raise TypeError
        if not o.is_saved():
            cls._new_objects.append(o)
        else:    
            cls._objects[o.key()]=o
        
    @classmethod
    def flush(cls):
        cls._new_objects.extend([o for o in cls._objects.values()]) 
        db.put(cls._new_objects)
        cls._objects={}
        cls._new_objects=[]
            
    @classmethod
    def objects(cls):
        return cls._objects
    
class Command(object):
    """
    (Abstract) Base class for all Commands. 
    
    Holds the game information, and handles the logging of game events.
    These game events are then broadcast to clients, to enable the real time updating of game events and messages.
    All Child classes should override the constructor(calling the base class constructor) with code performing any validition 
    (and throwing GameFlowException's on any invalid moves etc) and override the do method, performing any actual
    game object updates.
    """
    
    def __init__(self, game, player=None):
        """
        Should be passed a valid, started game model instance. 
        Child objects should override (with required args), call the base constructor, and perform any game move validation.
        """
        self.game=GameFlowCache.get(game)
        if player:
            self.player=GameFlowCache.get(player)
            if player != self._current_player():
                raise GameFlowException(-34500, "Only the current player can perform a command")
    
    def _current_player(self):
        """
        Handles getting the current player in a way that is consistant with the caching in GameFlowCache
        """
        try:
            while True:
                timeout_s = 0.1
                try:
                    player=[GameFlowCache.get(p) for p in self.game.players if GameFlowCache.get(p).is_current_player][0]
                    break;
                except db.Timeout:
                    logging.info("Got timeout fetching game state, trying again in %2f seconds" % timeout_s)
                    time.sleep(timeout_s)
                    timeout_s *= 2
        except apiproxy_errors.DeadlineExceededError:
            raise GameFlowException, "Timeout accessing the database"
        return player

    def _set_current_player(self, player):
        p=self._current_player()
        p.is_current_player=False
        GameFlowCache.add(p)
        if player:
            player.is_current_player=True
            GameFlowCache.add(player)

    def _start_player(self):
        """
        Handles getting the current player in a way that is consistant with the caching in GameFlowCache
        """
        try:
            while True:
                timeout_s = 0.1
                try:
                    player=[GameFlowCache.get(p) for p in self.game.players if GameFlowCache.get(p).is_start_player][0]
                    break;
                except db.Timeout:
                    logging.info("Got timeout fetching game state, trying again in %2f seconds" % timeout_s)
                    time.sleep(timeout_s)
                    timeout_s *= 2
        except apiproxy_errors.DeadlineExceededError:
            raise GameFlowException, "Timeout accessing the database"
        return player


    def _set_start_player(self, player):
        """
        Handles getting the start player in a way that is consistant with the caching in GameFlowCache
        """
        p=self._start_player()
        if p:
            p.is_start_player=False
            GameFlowCache.add(p)        
        player.is_start_player=True
        GameFlowCache.add(p)
        
    def _next_player(self):
        """
        Handles getting the next player in a way that is consistant with the caching in GameFlowCache
        """
        try:
            while True:
                timeout_s = 0.1
                try:
                    players=self.game.ordered_player_list(start_with_player=self._current_player())
                    next_players=[GameFlowCache.get(p) for p in players[1:] if not GameFlowCache.get(p).has_passed]
                    break;
                except db.Timeout:
                    logging.info("Got timeout fetching game state, trying again in %2f seconds" % timeout_s)
                    time.sleep(timeout_s)
                    timeout_s *= 2
        except apiproxy_errors.DeadlineExceededError:
            raise GameFlowException, "Timeout accessing the database"
        
        return next_players[0] if len(next_players) > 0 else None

    def _next_start_player(self):
        try:
            while True:
                timeout_s = 0.1
                try:
                    players=self.game.ordered_player_list(start_with_player=self._start_player())
                    break;
                except db.Timeout:
                    logging.info("Got timeout fetching game state, trying again in %2f seconds" % timeout_s)
                    time.sleep(timeout_s)
                    timeout_s *= 2
        except apiproxy_errors.DeadlineExceededError:
            raise GameFlowException, "Timeout accessing the database"

        return players[1]
    
    def _log(self, log_class, *args, **kwds):
        """
        Method to log game events. Should be passed a valid class derived from GameLogEntryBase (see gamelog.py), 
        with any proprty values passed as keyword args
        Automatically adds the game, timestamp, type and command properties.
        """
        kwds.update({"parent":self.game,"game":self.game, "timestamp":long(timestamp()), "type":log_class.__name__, "command":type(self).__name__})     
        log_entry=log_class(**kwds)
        GameFlowCache.add(log_entry)
    
    def do(self):
        """
        Child classes should override this class with the logic to perform commands. 
        Note that any setup or validation should be done in the constructor
        """
        raise NotImplementedError, "do must be overridden by the child class"
    
class CommandDelegate(object):
    """
    (Abstract) Base Class for all command Delegates.
    Is functionally equivilant to the Command class, but allows Command Classes to share functionality
    in a way that is much cleaner than using multiple inheritance. Commands that share functionality with multiple
    other commands should implement secondary functionality using a delegate. The delegates constructor should be passed the 
    calling command instance (i.e. it's self property), and then call the delegates do method within it's own do method.
    The delegate will then use the calling commands log method to log game actions.
    """ 

    def __init__(self, command, player=None):
        """
        Should be passed a the calling Command instance. 
        Child objects should override (with required args), call the base constructor, and perform any game move validation.
        """
        self.command=command
        if player:
            self.player=GameFlowCache.get(player)
            if player != command._current_player():
                raise GameFlowException(-34500, "Only the current player can perform a command")

    def _log(self, *args, **kwds):
        """
        Method to log game events. Should be passed a valid class derived from GameLogEntryBase (see gamelog.py), 
        with any property values passed as keyword args
        Automatically adds the game, timestamp, type and command properties.
        """
        self.command._log(*args, **kwds)    

    def do(self):
        """
        Child classes should override this class with the logic to perform commands. 
        Note that any setup or validation should be done in the constructor
        """
        raise NotImplementedError, "do must be overridden by the child class"
                
class GameFlow(object):
    """
    This is the (Abstract)Base class used to execute game flow logic (programs). 
    Child classes should override the _gameflow_program method, set _program_code=[]
    and use the public (i.e. no _) methods to build the gameflow program.
    The API handling the clients should initially call process() with no arguments to start the program
    The program will then execute until clien/user input is required and then suspend itself to the database.
    The API handling the client should then call process with any client commands, which will execute until 
    client input is required and so on and so forth until the program (and this the game) is finished.
    """
    def __init__(self, game):
        """Should be called with a valid gamestate model instance"""
        self.game=GameFlowCache.get(game)
        self.pc = self.game.program_counter
        self._gameflow_program()
        
    def _gameflow_program(self):
        """This should be overridden by the child class and set up the game logic using the  public (i.e. no _) methods to build the gameflow program."""
        raise NotImplementedError, "Gameflow_program must be overridden by the child class"
    
    def put(self):
        """Write the game state to the database"""
        self.game.program_counter=self.pc
        GameFlowCache.add(self.game)
        GameFlowCache.flush()
            
    def step(self):
        """Execute a single gameflow program instruction"""
        f=self._next_item()
        f()

    def process(self, command=None, *args, **kwds):
        """
        Execute the game flow until completion or the next expected client input is required.
        
        Should initially be called with no arguments to start the game. Subsequently should be called with a valid Command object,
        arguments to the command constructor should be supplied as further arguments or keywords        
        """ 
        if command:
            #Check that we are expecting a command
            if self._current_item() != self._expect:
                raise GameFlowException(-3401, "The Game flow was not expecting a command")
            
            #check that the command passed to us is what we expected
            expected_commands = self._program_code[self.pc+1] if isinstance(self._program_code[self.pc+1], type([])) else [self._program_code[self.pc+1]]
            match=False
            for expected_command in expected_commands:
                if command == expected_command or issubclass(command, expected_command):
                    match=True
            if not match:
                raise GameFlowException(-3402, "The Game flow was expecting commands %r, got %s" % ([e.__name__ for e in expected_commands], command.__name__))

            #Instantiate the command passed to us (along with any extra args)
            new_args=tuple([self.game]+list(args))
            c=command(*new_args, **kwds)

            #Everything seems Kosher, run the command and then increment the program counter ready for the next instruction
            c.do()
            self.pc+=3
            
        #Run the program until we hit the program end or an expect statement
        while True:
            if self._current_item()==self._expect: 
                #We have an expect statement
                #Check if there is a condition for waiting for the expect
                conditional_function=self._program_code[self.pc+2] 
                if (conditional_function==None or conditional_function()):
                    #The condition was true, stop here
                    break; 
                else:
                    #The condition was false, skip over the expect statement and continue
                    self.pc+=3
            if self._current_item()==self._end: 
                #We have an end statement, stop running the program
                break;
            self.step()

        
    
    def expect(self, command, when=None):
        """
        Expect a clients command. 
        
        command: a valid Command Class. 
        when: if supplied, it will be evaluated as a function and the command will only be required if it evaluates to true
        """
        self._program_code.extend([self._expect, command, when])

    def _expect(self):
        """Denotes that the game logic is expecting a clients command"""
        pass

    def end(self):
        """end the game flow"""
        self._program_code.extend([self._end])
        
    def _end(self):
        """Denotes the end of the game flow"""
        pass
    
    
    def while_(self, f):
        """
        Executes commands until the corresponding end_while command, as long as the supplied function evaluates to true.
        
        f:A function (or Lambda) to test for the continuation of the while loop
        """
        self._program_code.extend([self._while_, f])
    
    def _while_(self):
        """Executes the while command"""
        f=self._next_item()
        if not f(): #lambda passed to while is not true
            #skip to the matching end_while command..or the end of the program
            depth=1
            while (depth>0):
                self.pc+=1
                if self.pc==len(self._program_code):
                    raise Exception("while_ command without matching end_while")
                if self._program_code[self.pc]==self._end_while:
                    depth-=1
                elif self._program_code[self.pc]==self._while_:
                    depth+=1
            self.pc+=1
            
    def end_while(self):
        """Deontes the end of a while_ loop"""
        self._program_code.extend([self._end_while])
            
    def _end_while(self):
        """
        Indicates the end of a while_ "loop". 
        Searches backwards for the matching while command and sets the program counter to it.
        """
        depth=1
        self.pc-=1
        while (depth>0):
            self.pc-=1
            if self.pc==0:
                raise Exception("end_while without matching while_ command")
            if self._program_code[self.pc]==self._while_:
                depth-=1
            elif self._program_code[self.pc]==self._end_while:
                depth+=1        
                
    def set(self, who, what, f):
        """Set the value of who.what to the value returned by f()"""
        self._program_code.extend([self._set, who, what, f])
    
    def _set(self):
        """Sets an attribute to a value"""
        who, what, f=self._next_item(3)       
        setattr(GameFlowCache.get(who), what, f())
        GameFlowCache.add(who)

    def do(self, f):
        """Executes the supplied function. Generally should not be used and docmd should be used instead"""
        self._program_code.extend([self._do, f])
    
    def _do(self):
        """Executes the supplied function"""
        f=self._next_item()
        f()

    def docmd(self, command, *args, **kwds):
        """
        Executes the supplied Command class. Additional arguments will be passed to the commands constuctor.
        """
        when=kwds.pop("when", None)
        self._program_code.extend([self._docmd, command, args, kwds, when])
    
    def _docmd(self):
        """
        Executes a game command as part of the game flow, as opposed to a client executing am "expected" command.
        Useful for Passing, or any time complex updates to the game state are required to happen automatically without player input
        """
        command=self._next_item()
        args, kwds, when=self._next_item(3)
                
        if (when==None or when()):
            #Add the game object as the first argument to all commands
            new_args=tuple([self.game]+list(args))
            c=command(*new_args, **kwds)
            c.do()
            
    def print_(self, f):
        """prints a value to the log. Useful for debugging"""        
        self._program_code.extend([self._print_, f])
        
    def _print_(self):
        """prints a value to stdout. Useful for debugging"""
        f=self._next_item()
        logging.debug(f(self.game))
        
    def _next_item(self, count=None):
        """Increments the program counter and returns the next count items as a tuple, or the next item if count is not supplied"""
        if count:
            self.pc+=count
            return tuple(self._program_code[self.pc-count:self.pc])
        else:
            self.pc+=1
            return self._program_code[self.pc-1]

    def _current_item(self):
        """Returns the current program item"""
        return self._program_code[self.pc]

    def _previous_item(self):
        """Decrements the program counter and returns the previous item"""
        self.pc-=1
        return self._program_code[self.pc]

class BuildCommand(Command):
    """Handles player build commands, as part of the build phase"""
    def __init__(self, game, player, building):
        Command.__init__(self, game, player)
        if building not in BuildingTiles.tile_names():
            raise GameFlowException(-34501, "%s is not a valid building" % building)
        if GameFlowCache.get(self.game.buildingstock).building_count(building)==0:
            raise GameFlowException(-34502, "There are no buildings of type %s left" % building)
        self.player=GameFlowCache.get(player)
        playerboard=GameFlowCache.get(self.player.playerboard)
        build_level=playerboard.build_level
        required_level=BuildingTiles.level(building)
        minimum_level=GameFlowCache.get(self.game.buildingstock).minimum_level()        
        if build_level < required_level and required_level != minimum_level:
            raise GameFlowException(-34503, "You only have build level %d, require level %d to build %s." % (build_level, required_level, building))
        self.building=building

    def do(self):
        playerboard=GameFlowCache.get(self.player.playerboard)
        buildingstock=GameFlowCache.get(self.game.buildingstock)
        buildingstock.take_building(self.building)
        playerboard.add_building(self.building)
        GameFlowCache.add(playerboard)
        GameFlowCache.add(buildingstock)
        self._log(GameFlowLogEntry, message="Player %d (%s) built a %s" % (self.player.position, self.player.name, self.building))
        self._log(PlayerBuildingChangeLogEntry, position=self.player.position, add=self.building)

class PayCommand(Command):
    """Handles player pay commands, as part of the salary phase"""
    def __init__(self, game, player, buildings):
        Command.__init__(self, game, player)
        playerboard=GameFlowCache.get(self.player.playerboard)
        unpaid_buildings=[b for b,o in zip(playerboard.buildings, playerboard.buildings_occupied) if o==True]
        for b in buildings:
            try:
                index=unpaid_buildings.index(b)
            except ValueError:
                raise GameFlowException(-34511, "%s is not a valid unpaid building" % b)
            else:
                unpaid_buildings.pop(index)
        if (len(buildings) > playerboard.salary_level):
            raise GameFlowException(-34513, "You attempted to pay %d salaries, but your salary level is only %d" % (len(buildings), playerboard.salary_level))
        self.buildings=buildings

    def do(self):
        playerboard=GameFlowCache.get(self.player.playerboard)
        for building in self.buildings:
            #Get the index of the first occupied building of that type
            index=[i for i,b in enumerate(playerboard.buildings) if b==building and playerboard.buildings_occupied[i]==True][0]
            playerboard.buildings_occupied[index]=False
            playerboard.harbour_population+=1
        GameFlowCache.add(playerboard)
        self._log(GameFlowLogEntry, message="Player %d (%s) paid salary on  %s" % (self.player.position, self.player.name, ",".join(self.buildings)))
        self._log(PlayerBuildingChangeLogEntry, position=self.player.position, pay=self.buildings)                
      
class GrowthCommand(Command):
    """Handles the player Growth phase. Note this does not require player input and happens automatically as part of the game flow"""
    def __init__(self, game, player=None):
        Command.__init__(self, game)
        self.player=GameFlowCache.get(player or self._current_player())
        
    def do(self):
        playerboard=GameFlowCache.get(self.player.playerboard)
        growth=playerboard.growth_level+1
        playerboard.harbour_population+=growth
        GameFlowCache.add(playerboard)
        self._log(GameFlowLogEntry, message="Player %d (%s) added %d pop markers to their harbour" % (self.player.position, self.player.name, growth))
        self._log(PlayerGrowthLogEntry, position=self.player.position, growth=growth)

         
class ActionCommand(Command):
    """Base class that other commands from the Action phase are derived from"""
    def __init__(self, game, player):
        Command.__init__(self, game, player)
    
class ActivateBuildingCommand(ActionCommand):
    """Base class that other commands that activate buildings are derived from"""
    def __init__(self, game, player, building):
        ActionCommand.__init__(self, game, player)
        playerboard=GameFlowCache.get(self.player.playerboard)
        if building not in playerboard.buildings:
            raise GameFlowException(-34542, "You do not have a %s building" % building)
        building_index=playerboard.next_unoccupied_building_index(building)
        if building_index==None:
            raise GameFlowException(-34542, "Your do not have an unoccupied %s" % building)
        if playerboard.harbour_population == 0:
            raise GameFlowException(-34543, "You cannot occupy your %s as you have no population left" % building)
        if not BuildingTiles.action(building):
            raise GameFlowException(-34544, "There is no action associated with the %s building" % building)
        self.building=building
        
    def do(self):
        playerboard=GameFlowCache.get(self.player.playerboard)
        building_index=playerboard.next_unoccupied_building_index(self.building)
        playerboard.buildings_occupied[building_index]=True
        playerboard.harbour_population-=1
        GameFlowCache.add(playerboard)
        self._log(PlayerBuildingChangeLogEntry, position=self.player.position, occupy=[self.building])

class ShipCommandDelegate(CommandDelegate):
    """Command Delegate for Ship Commands, used by the Shipyard, Ship Tokens, Guild Hall Docks and Cartographer"""
    def __init__(self, command, player, region):
        CommandDelegate.__init__(self, command, player)
        if not region.shipping_track:
            raise GameFlowException(-34552, "%s does not have a shipping track" % region.name)
        self.command=command
        self.region=region
    
    def do(self):
        playerboard=GameFlowCache.get(self.player.playerboard)        
        playerboard.harbour_population-=1
        shipping_track=GameFlowCache.get(self.region.shipping_track)
        
        token=shipping_track.take_token(self.player)
        GameFlowCache.add(shipping_track)

        if (token):
            playerboard.add_token(token) 
            GameFlowCache.add(playerboard)

        self._log(GameFlowLogEntry, message="Player %d (%s) shipped to %s for a (%s) token" % (self.player.position, self.player.name, self.region.name, token))  

        if len(shipping_track.occupiers)==shipping_track.length: # If this is the last position on the shipping track
            #Iterate through all the players to determine the player with he most presence on the shipping track, 
            #or the highest position on the shipping track.
            governor_player=None;
            maxCount=0
            maxPosition=0
            for player in self.command.game.players:
                p=GameFlowCache.get(player)
                count=sum([1 for o in shipping_track.occupiers if o==p.key()] or [0])
                position=max([i for i,o in enumerate(shipping_track.occupiers) if o==p.key()] or [0])
                if count > maxCount or (count==maxCount and position>maxPosition):
                    governor_player=p
                    maxCount=count
                    maxPosition=position
            #And give them the governor card
            governor_card=GameFlowCache.get(self.region.card_pile).take_card()
            GameFlowCache.add(self.region.card_pile)
            governor_playerboard=GameFlowCache.get(governor_player.playerboard)
            governor_playerboard.add_card(governor_card)
            GameFlowCache.add(governor_playerboard)
            self._log(GameFlowLogEntry, message="The shipping track for region %s is now full, and the governor card has been awarded to player %d (%s)" %(self.region.name, governor_player.position, governor_player.name))  
            self._log(CardPileChangeLogEntry, region=self.region.number, position=governor_player.position, use_slavery_pile=False, remove=governor_card)
            
        self._log(ShippingTrackChangeLogEntry, region=self.region.number, player=self.player.position, token=token)
   

class ActivateBuildingShipCommand(ActivateBuildingCommand):
    """Handles the Ship Command for the shipyard, guildhall, docks and cartographer """
    def __init__(self, game, player, building, region_number):
        ActivateBuildingCommand.__init__(self, game, player, building)
        if "s" not in BuildingTiles.action(building):
            raise GameFlowException(-34552, "Building %s can not ship" % building)
        #Normally we would flusg the game cache for a db read but this is ok as the gamestate never alters the region makeup            
        region=GameFlowCache.get(game.boardstate.regions.filter("number =", region_number).get())
        if not region:
            raise GameFlowException(-34551, "Region %s does not exist" % str(region_number))
        if GameFlowCache.get(self.player.playerboard).harbour_population < 2:
            raise GameFlowException(-34553, "You cannot ship as you only have 1 population left")
        self.ship_command_delegate=ShipCommandDelegate(self, self.player, region)

    def do(self):
        ActivateBuildingCommand.do(self)
        self.ship_command_delegate.do()

class ActivateBuildingShipAndShipCommand(ActivateBuildingCommand):
    """Handles the Ship+Ship Command for the cartographer """
    def __init__(self, game, player, building, region_number):
        ActivateBuildingCommand.__init__(self, game, player, building)
        if BuildingTiles.action(building)!="s+s":
            raise GameFlowException(-34552, "Building %s can not ship & ship" % building)            
        self.region=GameFlowCache.get(game.boardstate.regions.filter("number =", region_number).get())
        if not self.region:
            raise GameFlowException(-34551, "Region %s does not exist" % str(region_number))
        if GameFlowCache.get(self.player.playerboard).harbour_population < 3:
            raise GameFlowException(-34554, "You cannot occupy+ship as you do not have 3 population left")
        self.ship_command_delegate_1=ShipCommandDelegate(self, player, self.region)
        self.ship_command_delegate_2=ShipCommandDelegate(self, player, self.region)
        
    def do(self):
        ActivateBuildingCommand.do(self)
        self.ship_command_delegate_1.do()
        self.ship_command_delegate_2.do()

class ActivateBuildingOccupyAndShipCommand(ActivateBuildingCommand):
    """Handles the Ship Command for the shipyard, guildhall, docks and cartographer """
    def __init__(self, game, player, building, city_number, region_number):
        ActivateBuildingCommand.__init__(self, game, player, building)
        if BuildingTiles.action(building)!="o+s":
            raise GameFlowException(-34552, "Building %s can not occupy & ship" % building)            
        self.region=GameFlowCache.get(game.boardstate.regions.filter("number =", region_number).get())
        if not self.region:
            raise GameFlowException(-34551, "Region %s does not exist" % str(region_number))
        self.city=GameFlowCache.get(game.boardstate.cities.filter("number =", city_number).get())
        if not self.city:
            raise GameFlowException(-34561, "City %d does not exist" % city_number)
        if GameFlowCache.get(player.playerboard).harbour_population < 3:
            raise GameFlowException(-34554, "You cannot occupy+ship as you do not have 3 population left")
        if self.city.region != self.region:
            raise GameFlowException(-34556, "You cannot occupy+ship as city %d is not in region %d"  %(city_number, region_number))        
        self.ship_command_delegate=ShipCommandDelegate(self, self.player, self.region)
        self.occupy_command_delegate=OccupyCommandDelegate(self, self.player, self.city, True)
        
    def do(self):
        ActivateBuildingCommand.do(self)
        self.ship_command_delegate.do()
        self.occupy_command_delegate.do()
        
class CityCommandDelegate(CommandDelegate):
    """Command Delegate to handle city connection changes, used by all occupy and attack commands"""
    def check_city_connection(self):
        city=self.city
        connections=[GameFlowCache.get(con) for con in city.connections()]
        if connections:
            for connection in connections:
                other_end = GameFlowCache.get(connection.b_end) if GameFlowCache.get(connection.a_end)==city else GameFlowCache.get(connection.a_end)
                displace = None
                occupy=None
                token = None
                if other_end.occupier==self.player:
#                    connection=Connection.all().filter('a_end in', (city, other_end)).filter('b_end in', (city, other_end)).get()
                    if connection.occupier and connection.occupier != self.player:
                        displace=connection.occupier.position
                        occupy=self.player.position
                        self._log(GameFlowLogEntry, message="Player %d (%s) occupied the connection between %s and %s, displacing player %d (%s)" % (self.player.position, self.player.name, city.name, other_end.name, connection.occupier.position, connection.occupier.name))
                        connection.occupier=self.player
                        GameFlowCache.add(connection)
                    elif connection.trade_token:
                        playerboard=GameFlowCache.get(self.player.playerboard)                
                        token=connection.take_token()
                        occupy=self.player.position
                        self._log(GameFlowLogEntry, message="Player %d (%s) occupied the connection between %s and %s, taking token (%s)" % (self.player.position, self.player.name, city.name, other_end.name, token))
                        connection.occupier=self.player
                        GameFlowCache.add(connection)
                        playerboard.add_token(token) 
                        GameFlowCache.add(playerboard)
                    elif connection.occupier != self.player:
                        occupy=self.player.position
                        connection.occupier=self.player
                        GameFlowCache.add(connection)
                elif connection.occupier and connection.occupier!=self.player:
                        displace=GameFlowCache.get(connection.occupier).position
                        self._log(GameFlowLogEntry, message="Player %d (%s) displaced player %d (%s) from the connection between %s and %s, " % (self.player.position, self.player.name, connection.occupier.position, connection.occupier.name, city.name, other_end.name))
                        connection.occupier=None
                        GameFlowCache.add(connection)
                if displace or occupy or token:
                    self._log(ConnectionChangeLogEntry, a_end=connection.a_end.number, b_end=connection.b_end.number, occupy=occupy, displace=displace, take=token)                

class OccupyCommandDelegate(CityCommandDelegate):
    """Command delegate to handle city occupations, used by the colonialhouse, docks, fortress and occupy tokens"""
    def __init__(self, command, player, city, is_occupy_and_ship=False):
        CityCommandDelegate.__init__(self, command, player)
        if city.occupier:
            raise GameFlowException(-34562, "You cannot occupy %s is already occupied" % city.name)
        #We need to flush the cache to the disk so we can calculate region.is_open and presence
        GameFlowCache.flush()
        city_region=GameFlowCache.get(city.region)
        if not city_region.is_open(is_occupy_and_ship):
            raise GameFlowException(-34563, "You cannot occupy %s as region %s is not open yet" % (city.name, city_region.name))
        if GameFlowCache.get(city_region).number != 0 and city_region.presence(player) == 0 and not is_occupy_and_ship:
            raise GameFlowException(-34564, "You cannot occupy %s as you have no presence in the region %s" % (city.name, city_region.name))
        if GameFlowCache.get(player.playerboard).harbour_population < 1:
            raise GameFlowException(-34553, "You cannot occupy %s as you have no population left" % city.name)
        self.city=city
    
    def do(self):
        playerboard=GameFlowCache.get(self.player.playerboard)        
        playerboard.harbour_population-=1
       
        token=self.city.take_token(self.player)
        GameFlowCache.add(self.city)
                        
        playerboard.add_token(token) 
        GameFlowCache.add(playerboard)        
        
        self._log(GameFlowLogEntry, message="Player %d (%s) occupied %s for a (%s) token" % (self.player.position, self.player.name, self.city.name, token))  
        self._log(CityChangeLogEntry, city=self.city.number, take=token, occupy=self.player.position)
        self.check_city_connection()    

class AttackCommandDelegate(CityCommandDelegate):
    """Command delegate to handle city attacks, used by the barracks, fortress and attack tokens"""
    def __init__(self, command, player, city):
        CityCommandDelegate.__init__(self, command, player)
        if  not city.occupier:
            raise GameFlowException(-34522, "You cannot attack %s as it is not occupied" % city.name)
        if  city.occupier==self.player:
            raise GameFlowException(-34526, "You cannot attack %s as you occupy it" % city.name)
        # We have to flush the cache to disk so we can check if a region is open and calculate presence
        GameFlowCache.flush()
        city_region=GameFlowCache.get(city.region)
        if not city_region.is_open():
            raise GameFlowException(-34523, "You cannot attack %s as region %s is not open yet" % (city.name, city.region.name))
        if city_region.number != 0 and city_region.presence(player) == 0:
            raise GameFlowException(-34524, "You cannot attack %s as you have no presence in the region %s" % (city.name, city.region.name))
        if GameFlowCache.get(player.playerboard).harbour_population < 2:
            raise GameFlowException(-34513, "You cannot attack %s as you do not have 2 population left" % city.name)
        self.city=city
    
    def do(self):
        playerboard=GameFlowCache.get(self.player.playerboard)        
        playerboard.harbour_population-=2
        GameFlowCache.add(playerboard)
        
        old_occupier=self.city.attack(self.player)
        GameFlowCache.add(self.city)
                                
        self._log(GameFlowLogEntry, message="Player %d (%s) attacked city %s, displacing player %d (%s)" % (self.player.position, self.player.name, self.city.name, old_occupier.position, old_occupier.name))  
        self._log(CityChangeLogEntry, city=self.city.number, attack=self.player.position)
        self.check_city_connection()
            
class ActivateBuildingOccupyCommand(ActivateBuildingCommand):
    """Command to handle the occupy command, used by the colonialhouse, docks and fortress"""
    def __init__(self, game, player, building, city_number):
        ActivateBuildingCommand.__init__(self, game, player, building)
        if "o" not in BuildingTiles.action(building):
            raise GameFlowException(-34552, "Building %s can not occupy" % building)            
        city=GameFlowCache.get(game.boardstate.cities.filter("number =", city_number).get())
        if not city:
            raise GameFlowException(-34561, "City %d does not exist" % city_number)
        if GameFlowCache.get(player.playerboard).harbour_population < 2:
            raise GameFlowException(-34553, "You cannot occupy as you only have 1 population left")
        self.occupy_command_delegate=OccupyCommandDelegate(self, self.player, city)
        
    def do(self):
        ActivateBuildingCommand.do(self)
        self.occupy_command_delegate.do()
        
class DrawCommandDelegate(CommandDelegate):
    """Command Delegate for all card drawing commands. Used by the draw Token, Market, Guild Hall and Trade Office"""
    def __init__(self, command, player, region, use_slavery_pile, second_draw=False):
        CommandDelegate.__init__(self, command, player)
        # We need to flush the cache to disk so we can calculate whether the region is open
        GameFlowCache.flush()
        self.region=GameFlowCache.get(region)
        if not self.region.is_open():
            raise GameFlowException(-34573, "You cannot draw from region %s as it is not open yet" % (self.region.name))
        self.card_pile=GameFlowCache.get(region.slavery_card_pile) if (self.region and use_slavery_pile) else GameFlowCache.get(region).card_pile
        if not self.card_pile:
            raise GameFlowException(-34575, "There is no %s card pile in region %s" % ("slavery " if use_slavery_pile else "", self.region.name))
        next_card=self.card_pile.next_next_card() if second_draw else self.card_pile.next_card(); 
        if next_card==None:
            raise GameFlowException(-34576, "There are no cards left in the %s%s pile" % (region.name," slavery" if use_slavery_pile else ""))
        #We Must flush the GameFlowCache to disk to calcaulte the region presence.
        GameFlowCache.flush() 
        if self.region.presence(self.player) < CardDeck.card_level(next_card):
            raise GameFlowException(-34574, "You cannot draw card %s as you do not have enough presence in the region %s" % (next_card, region.name))

        self.command=command
        self.use_slavery_pile=use_slavery_pile
    
    def do(self):
        playerboard=GameFlowCache.get(self.player.playerboard)        
       
        card=self.card_pile.take_card()
        GameFlowCache.add(self.card_pile)
        
        playerboard.add_card(card)
        GameFlowCache.add(playerboard)
        self._log(GameFlowLogEntry, message="Player %d (%s) drew the card %s from %s" % (self.player.position, self.player.name, card, "the slavery pile" if self.use_slavery_pile else self.region.name))  
        self._log(CardPileChangeLogEntry, region=self.region.number, position=self.player.position, use_slavery_pile=self.use_slavery_pile, remove=card)
        
        if card=="eu5": # Abolution of Slavery Occurs when card eu5 is drawn
            self._log(GameFlowLogEntry, message="The final card has been drawn from the Europe & the Mediterranean stack. Slavery has been abolished.")
            boardstate=GameFlowCache.get(self.command.game.boardstate)
            boardstate.slavery_abolished=True;
            GameFlowCache.add(boardstate)
            #Remove all slavery cards from the game
            slavery_pile=GameFlowCache.get(boardstate.regions.filter("number =",0).get()).slavery_card_pile
            slavery_pile.cards=[]
            GameFlowCache.add(slavery_pile)
            self._log(GameFlowLogEntry, message="All Slavery cards are removed from play.")
            self._log(AbolishSlaveryLogEntry)
            
            #Discard all player slavery cards
            for p in self.command.game.players:
                playerboard=GameFlowCache.get(p.playerboard)
                slavery_cards=[c for c in playerboard.cards if c[0:2]=="sl"]
                if len(slavery_cards)>0:
                    playerboard.cards=[c for c in playerboard.cards if c[0:2]!="sl"]
                    playerboard.discarded_slavery_cards.extend(slavery_cards)
                    GameFlowCache.add(playerboard)
                    self._log(GameFlowLogEntry, message="Player %d (%s) discarded slavery cards %r" % (p.position, p.name, slavery_cards))
                    self._log(PlayerDiscardLogEntry, position=p.position, discard=slavery_cards, pass_player=False)

class ActivateBuildingDrawCommand(ActivateBuildingCommand):
    """Handles the Activate Market Command"""
    def __init__(self, game, player, building, region_number, use_slavery_pile=False):
        ActivateBuildingCommand.__init__(self, game, player, building)
        if "d" not in BuildingTiles.action(building):
            raise GameFlowException(-34552, "Building %s can not draw" % building)
        region=GameFlowCache.get(game.boardstate.regions.filter("number =", region_number).get())
        if not region:
            raise GameFlowException(-34571, "Region %s does not exist" % str(region_number))
        self.draw_command_delegate=DrawCommandDelegate(self, player, region, use_slavery_pile)
        
    def do(self):
        ActivateBuildingCommand.do(self)
        self.draw_command_delegate.do()

class ActivateBuildingDrawAndDrawCommand(ActivateBuildingCommand):
    """Handles the Activate trade office Command"""
    def __init__(self, game, player, building, region_number, use_slavery_pile_1=False, use_slavery_pile_2=False):
        ActivateBuildingCommand.__init__(self, game, player, building)
        if BuildingTiles.action(building)!="d+d":
            raise GameFlowException(-34552, "Building %s can not draw+draw" % building)
        region=GameFlowCache.get(game.boardstate.regions.filter("number =", region_number).get())
        if not region:
            raise GameFlowException(-34571, "Region %s does not exist" % str(region_number))
        self.draw_command_delegate_1=DrawCommandDelegate(self, player, region, use_slavery_pile_1)
        self.draw_command_delegate_2=DrawCommandDelegate(self, player, region, use_slavery_pile_2, use_slavery_pile_1==use_slavery_pile_2)
        
    def do(self):
        ActivateBuildingCommand.do(self)
        self.draw_command_delegate_1.do()
        self.draw_command_delegate_2.do()

class ActivateBuildingAttackCommand(ActivateBuildingCommand):
    """Handles the Attack Command for the barracks and fortress"""
    def __init__(self, game, player, building, city_number):
        ActivateBuildingCommand.__init__(self, game, player, building)
        if "a" not in BuildingTiles.action(building):
            raise GameFlowException(-34552, "Building %s can not attack" % building)
        city=GameFlowCache.get(game.boardstate.cities.filter("number =", city_number).get())
        if not city:
            raise GameFlowException(-34561, "City %d does not exist" % city_number)
        if GameFlowCache.get(player.playerboard).harbour_population < 3:
            raise GameFlowException(-34553, "You cannot attack as you do not have 3 population left")
        self.attack_command_delegate=AttackCommandDelegate(self, player, city)
        
    def do(self):
        ActivateBuildingCommand.do(self)
        self.attack_command_delegate.do()

class PayCommandDelegate(CommandDelegate):
    """Command delegate to handle pay command for Pay Tokens and the Exchange, Meseum and Parliament"""
    def __init__(self, command, player, building):
        CommandDelegate.__init__(self, command, player)
        playerboard=GameFlowCache.get(self.player.playerboard)
        unpaid_buildings=[b for b,o in zip(playerboard.buildings, playerboard.buildings_occupied) if o==True]
        try:
            unpaid_buildings.index(building)
        except ValueError:
            raise GameFlowException(-34511, "%s is not a valid unpaid building" % building)
        self.building=building    
     
    def do(self):
        #Get the index of the first occupied building of that type
        playerboard=GameFlowCache.get(self.player.playerboard)
        index=[i for i,b in enumerate(playerboard.buildings) if b==self.building and playerboard.buildings_occupied[i]==True][0]
        playerboard.buildings_occupied[index]=False
        playerboard.harbour_population+=1
        GameFlowCache.add(playerboard)
        self._log(PlayerBuildingChangeLogEntry, position=self.player.position, pay=[self.building])                

class ActivateBuildingPayCommand(ActivateBuildingCommand):
    """Handles the Pay Command for the Exchange, Museum and Parliament"""
    def __init__(self, game, player, building, target_building):
        ActivateBuildingCommand.__init__(self, game, player, building)
        if BuildingTiles.action(building)!="p":
            raise GameFlowException(-31552, "Building %s can not pay" % building)
        if GameFlowCache.get(player.playerboard).harbour_population < 1:
            raise GameFlowException(-34553, "You cannot pay as you have no population left")
        self.pay_command_delegate=PayCommandDelegate(self, player, target_building)
        self.building=building
        self.target_building=target_building
        
    def do(self):
        ActivateBuildingCommand.do(self)
        self._log (GameFlowLogEntry, message="Player %d (%s) used thier %s to pay salary on thier %s" % (self.player.position, self.player.name, self.building, self.target_building))
        self.pay_command_delegate.do()

class UseActionTokenCommand(ActionCommand):
    """Base class for all Action Token Commands"""
    def __init__(self, game, player, token, action):
        ActionCommand.__init__(self, game, player)
        playerboard=GameFlowCache.get(self.player.playerboard)
        if token not in playerboard.harbour_tokens:
            raise GameFlowException(-34582, "You do not have a %s token in your harbour" % token)
        if action not in TokenBag.actions(token):
            raise GameFlowException(-34583, "You cannot use a %s token to perform the action %s" % (token, action))
        self.token=token
            
    def do(self):
        playerboard=GameFlowCache.get(self.player.playerboard)
        playerboard.remove_token(self.token)
        GameFlowCache.add(playerboard)
        self._log(PlayerTokenChangeLogEntry, position=self.player.position, remove=[self.token])

class UseDrawTokenCommand(UseActionTokenCommand):
    """Command to handle the draw command for Ship/Draw or Occupy/Draw tokens"""
    def __init__(self, game, player, token, region_number, use_slavery_pile=False):
        UseActionTokenCommand.__init__(self, game, player, token, "draw")
        region=GameFlowCache.get(game.boardstate.regions.filter("number =", region_number).get())
        if not region:
            raise GameFlowException(-34571, "Region %s does not exist" % str(region_number))
        self.draw_command_delegate=DrawCommandDelegate(self, self.player, region, use_slavery_pile)
    
    def do(self):
        UseActionTokenCommand.do(self)
        self.draw_command_delegate.do()

class UseShipTokenCommand(UseActionTokenCommand):
    """Command to handle the ship command for ship/draw tokens"""
    def __init__(self, game, player, token, region_number):
        UseActionTokenCommand.__init__(self, game, player, token, "ship")
        region=GameFlowCache.get(game.boardstate.regions.filter("number =", region_number).get())
        if not region:
            raise GameFlowException(-34571, "Region %s does not exist" % str(region_number))
        if GameFlowCache.get(player.playerboard).harbour_population < 1:
            raise GameFlowException(-34573, "You cannot ship as you only have no population left")
        self.ship_command_delegate=ShipCommandDelegate(self, self.player, region)
    
    def do(self):
        UseActionTokenCommand.do(self)
        self.ship_command_delegate.do()

class UseOccupyTokenCommand(UseActionTokenCommand):
    """Command to handle the occupy command for occupy/draw tokens"""
    def __init__(self, game, player, token, city_number):
        UseActionTokenCommand.__init__(self, game, player, token, "occupy")
        city=GameFlowCache.get(game.boardstate.cities.filter("number =", city_number).get())
        if not city:
            raise GameFlowException(-34581, "City %d does not exist" % city_number)
        if GameFlowCache.get(player.playerboard).harbour_population < 1:
            raise GameFlowException(-34583, "You cannot occupy as you only no population left")
        self.occupy_command_delegate=OccupyCommandDelegate(self, self.player, city)
    
    def do(self):
        UseActionTokenCommand.do(self)
        self.occupy_command_delegate.do()   

class UseAttackTokenCommand(UseActionTokenCommand):
    """Command to handle the attack command for attack tokens"""
    def __init__(self, game, player, token, city_number):
        UseActionTokenCommand.__init__(self, game, player, token, "attack")
        city=GameFlowCache.get(game.boardstate.cities.filter("number =", city_number).get())
        if not city:
            raise GameFlowException(-34581, "City %d does not exist" % city_number)
        if GameFlowCache.get(player.playerboard).harbour_population < 2:
            raise GameFlowException(-34583, "You cannot attack as you do not have 2 population left")
        self.attack_command_delegate=AttackCommandDelegate(self, self.player, city)
    
    def do(self):
        UseActionTokenCommand.do(self)
        self.attack_command_delegate.do()   
        
class UsePayTokenCommand(UseActionTokenCommand):
    """Command to handle the occupy command for occupy/draw tokens"""
    def __init__(self, game, player, token, building):
        UseActionTokenCommand.__init__(self, game, player, token, "pay")
        self.pay_command_delegate=PayCommandDelegate(self, self.player, building)
        self.building=building
        
    def do(self):
        UseActionTokenCommand.do(self)
        self.pay_command_delegate.do()
        self._log (GameFlowLogEntry, message="Player %d (%s) used a pay token on thier  %s" % (self.player.position, self.player.name, self.building))

class DiscardCommand(Command):
    """Command to handle the discard command, required when players have exceeded thier card limit at the end of the action phase"""
    def __init__(self, game, player, card_list):
        Command.__init__(self, game, player)
        temp_playerboard=copy.copy(GameFlowCache.get(self.player.playerboard))
        if len(card_list) != len(set(card_list)):
                raise GameFlowException(-33583, "Player %d attempted to discard the same card more than once." % (player.position))            
        for c in card_list:
            if c not in temp_playerboard.cards:
                raise GameFlowException(-33581, "Player %d does not have the card %s" % (player.position, c))
            
        #Remove the card temporarily so we can check that the card limit will be valid after the cards are removed
        temp_playerboard.cards=[pc for pc in temp_playerboard.cards if not [c for c in card_list if pc == c]]
        if temp_playerboard.card_limit_exceeded:
            raise GameFlowException(-33582, "Player %d's card limit is still exceeded after removing cards %r. Remove more cards." % (player.position, card_list))
        
        if temp_playerboard.card_count() < temp_playerboard.card_limit:
            raise GameFlowException(-33584, "Player %d cannot remove more cards than necessary. Remove less cards" % (player.position))
            
        self.card_list=card_list        
        
    def do(self):
        playerboard=GameFlowCache.get(self.player.playerboard)
        #remove the cards from the playerboard cards array, and put them in the discarded slavery cards array
        playerboard.cards=[pc for pc in playerboard.cards if pc not in self.card_list]
        #re-add relevant cards to their card piles
        for card in self.card_list:
            if card[0:2]=="sl": # Add slavery cards to the players discard stack
                playerboard.discarded_slavery_cards.append(card)
            elif card[0:2]!="eu" and card[2]=="0": #Don't add govenor cards
                boardstate=GameFlowCache.get(self.game.boardstate)
                boardstate.discarded_governor_cards.append(card)
                GameFlowCache.add(boardstate)
            else:
                #Normally We must flush the game flow cache as get_region_by_id reads from the database
                #However region id's do not change during the game flow so we can comment this out
                #GameFlowCache.flush()
                card_pile=GameFlowCache.get(self.game.boardstate.get_region_by_id(card[0:2]).card_pile)
                card_pile.put_card(card)
                GameFlowCache.add(card_pile)
            GameFlowCache.add(playerboard)
        
        self._log(GameFlowLogEntry, message="Player %d Discarded cards %r" % (self.player.position, self.card_list))
        self._log(PlayerDiscardLogEntry, position=self.player.position, discard=self.card_list, pass_player=True)
        
class PassBaseCommand(Command):
    """Abstract Base class to handle Pass and Auto Pass commands"""
    def _pass_player(self, message, auto_pass=False):
        self.player.has_passed=True
        GameFlowCache.add(self.player)
        discard_required=self.game.phase=="action" and GameFlowCache.get(self.player.playerboard).card_limit_exceeded
        self._log (GameFlowLogEntry, message=message)
        self._log(PlayerPassLogEntry, position=self.player.position, auto_pass=auto_pass, phase=self.game.phase, discard_required=discard_required)

        if discard_required:
            self._log (GameFlowLogEntry, message="Player %d has exceeded thier card limit and must discard cards" % self.player.position)

     
class PassCommand(PassBaseCommand):
    """Command to handle the pass command, either as an expected command from the player, or as directed by the game flow"""
    def __init__(self, game, player=None):
        PassBaseCommand.__init__(self, game)
        if player:
            if player != self._current_player():
                raise GameFlowException(-34540, "Only the current player can pass")
        else:
            player=self._current_player()
        self.player=player 
        
    def do(self):
        self._pass_player("Player %d passed" % self.player.position);
        
class AutoPassCommand(PassBaseCommand):
    """Command to automatically pass a player if they have no possible actions left, as directed by the game flow"""
    def __init__(self, game):
        Command.__init__(self, game)
        self.player=self._current_player()
        
    def do(self):
        playerboard=GameFlowCache.get(self.player.playerboard)
        if self.game.phase=="action":
            if playerboard.harbour_population==0 and len(playerboard.harbour_tokens)==0:
                self._pass_player("Player %d auto passed the action phase as they had no remaining population and no action tokens" % self.player.position, True)
            elif all(o==True for b,o in zip(playerboard.buildings, playerboard.buildings_occupied) if BuildingTiles.action(b) != "") and len(playerboard.harbour_tokens)==0:
                self._pass_player("Player %d auto passed the action phase as they had no unoccupied buildings and no action tokens" % self.player.position, True)
        elif self.game.phase=="salary":
            if all([b==False for b in playerboard.buildings_occupied]):
                self._pass_player("Player %d auto passed the salary phase as they had no occupied buildings" % self.player.position, True)
                   
class NextPlayerCommand(Command):
    """Command to set the next player as the current player, as directed by the game flow"""
    def __init__(self, game):
        Command.__init__(self, game)
        self.next_player=self._next_player()
            
    def do(self):
        if self.next_player: #Sometimes there is no next player, for e.g. when everyone has passed before a new phase
            self._set_current_player(self.next_player)
            self._log(GameFlowLogEntry, message="Next Player is player %d (%s)" % (self.next_player.position, self.next_player.name))
            self._log(CurrentPlayerLogEntry, position=self.next_player.position, phase=self.game.phase)
        else:
            current_player=self._current_player()
            if current_player: #Log an entry if we still have a current player so the app knows we are on another iteation of the phase.
                self._log(GameFlowLogEntry, message="Current player is still player %d (%s)" % (current_player.position, current_player.name))
                self._log(CurrentPlayerLogEntry, position=current_player.position, player_changed=False)

class PlayerPhaseStartCommand(Command):
    """Command to cleanly indicate the start of a players turn"""
    def __init__(self, game):
        Command.__init__(self, game)
        
    def do(self):
        current_player=self._current_player();
        self._log(PlayerPhaseStartLogEntry, position=current_player.position, round=self.game.round, phase=self.game.phase)
        
class NextRoundCommand(Command):
    """Command to increment the round counter, as directed by the game flow"""
    def __init__(self, game):
        Command.__init__(self, game)
        
    def do(self):
        self.game.round += 1
        GameFlowCache.add(self.game)
        
        next_start_player=self._next_start_player()
        self._set_start_player(next_start_player)
        self._set_current_player(next_start_player)
        self._log(GameFlowLogEntry, message="Starting Round %d, start player is now player  %d (%s)" % (self.game.round,next_start_player.position, next_start_player.name))
        self._log(NextRoundLogEntry, round=self.game.round, start_player=next_start_player.position)
    
class ResetPassedPlayersCommand(Command):
    """Command to reset all player passed flags, as directed by the game flow"""
    def __init__(self, game):
        Command.__init__(self, game)
        
    def do(self):        
        for p in [GameFlowCache.get(pp) for pp in self.game.players]:
            p.has_passed=False
            GameFlowCache.add(p)

        self._set_current_player(self._start_player())
        self._log(GameFlowLogEntry, message="Current player is now player %d (%s)" % (self._current_player().position,  self._current_player().name))  
        self._log(CurrentPlayerLogEntry, position=self._current_player().position)

class NewPhaseCommand(Command):
    "Command to set the phase to a new phase, as directed by the game flow"""
    def __init__(self, game, phase, reset_passed_players=True):
        Command.__init__(self, game)
        self.phase=phase
        self.reset_passed_players=reset_passed_players
        
    def do(self):
        self.game.phase = self.phase
        GameFlowCache.add(self.game)
        if self.reset_passed_players:
            current_player=self._current_player()
            if current_player.has_passed:
                current_player.has_passed=False
                GameFlowCache.add(current_player)
        self._log(GameFlowLogEntry, message="Entering phase %s" % self.phase)  
        self._log(NewPhaseLogEntry, phase=self.phase)

class EndGameCommand(Command):
    """Command to end the game and calculate all the players scores, as directed by the game flow"""
    def __init__(self, game):
        Command.__init__(self, game)
        
    def do(self):
        self.game.phase="gameover"
        self._set_current_player(None)
        GameFlowCache.add(self.game)
        #Flush the game flow cache to disk so we can query the database
        GameFlowCache.flush()
        self._log(GameFlowLogEntry, message="The game is finished")
        self._log(NewPhaseLogEntry, phase=self.game.phase)
        player_scores=[ScoreCalculator(self.game, p) for p in self.game.players]
        finish_position=1
        last_score=0
        winners=[]
        for player_score in sorted(player_scores, cmp=lambda x, y: 1 if x.total > y.total else 0 if x.total==y.total else -1, reverse=True):
            p=self.game.players.filter("position =",player_score.position).get()
            self._log(GameFlowLogEntry, message="Player %d (%s) scored %r" % (p.position, p.name, player_score) )
            if finish_position==1: 
                winners.append(p)
                winning_score=player_score.total
            
            PlayerScore(game=self.game, player=p, finish_position=finish_position,
                      industry=player_score.industry,culture=player_score.culture,
                      finance=player_score.finance,politics=player_score.politics,occupied_cities=player_score.occupied_cities,
                      controlled_connections=player_score.controlled_connections,card_glory=player_score.card_glory,
                      free_govenor=player_score.free_govenor,building_glory=player_score.building_glory,
                      extra_population=player_score.extra_population,slavery=player_score.slavery,total=player_score.total).put()

            if player_score.total!=last_score:
                finish_position+=1
                
            last_score=player_score.total


        if (len(winners)==1):
            self._log(GameFlowLogEntry, message="The winner was player %d (%s) with %d points" % (winners[0].position, winners[0].name, winning_score))
        else:
            n=" and ".join(["player %d (%s)" % (p.position,p.name) for p in winners])
            self._log(GameFlowLogEntry, message="The Game was a tie between %s with %d points" % (n, winning_score))

class EndeavorGameFlow(GameFlow):
    """This is the main game flow program for Endeavor."""     
    def _gameflow_program(self):
        self._program_code=[]
        self.set(self.game, "round",  lambda: 1)
        
        self.while_(lambda: self.game.round <= 7)

        self.docmd(ResetPassedPlayersCommand)
        
        self.while_(lambda: any([GameFlowCache.get(p).has_passed==False for p in list(self.game.players)])) #All players have not passed
        self.docmd(NewPhaseCommand, "build")
        self.docmd(PlayerPhaseStartCommand)
        self.expect([BuildCommand])
        self.docmd(NewPhaseCommand, "growth")
        self.docmd(PlayerPhaseStartCommand)
        self.docmd(GrowthCommand)
        self.docmd(NewPhaseCommand, "salary")
        self.docmd(AutoPassCommand) # Automatically pass the player if they have no salary to pay
        self.docmd(PlayerPhaseStartCommand, when=lambda: self.current_player().has_passed==False)
        self.expect([PayCommand, PassCommand], when=lambda: self.current_player().has_passed==False)
        self.docmd(PassCommand) 
        self.docmd(NextPlayerCommand)
        self.end_while()
        
        self.docmd(NewPhaseCommand, "action")
        self.docmd(ResetPassedPlayersCommand)

        self.while_(lambda: any([GameFlowCache.get(p).has_passed==False for p in list(self.game.players)])) #All players have not passed
        self.docmd(PlayerPhaseStartCommand, when=lambda: self.current_player().has_passed==False)
        self.docmd(AutoPassCommand) # Automatically pass the player if they have no possible game actions left
        self.expect([ActionCommand, PassCommand], when=lambda: self.current_player().has_passed==False)
        self.docmd(NewPhaseCommand, "discard", False, when=lambda: self.current_player().has_passed==True
                    and GameFlowCache.get(self.current_player().playerboard).card_limit_exceeded)
        self.docmd(PlayerPhaseStartCommand, when=lambda: self.game.phase=="discard")
        self.expect(DiscardCommand, when=lambda: self.game.phase=="discard")
        self.docmd(NewPhaseCommand, "action", False, when=lambda: self.game.phase=="discard")
        self.docmd(NextPlayerCommand)
        self.end_while()
        
        self.docmd(NextRoundCommand)
        
        self.end_while()
        self.docmd(EndGameCommand)
        self.end()

    def current_player(self):
        """
        Handles getting the current player in a way that is consistant with the caching in GameFlowCache
        """
        return [GameFlowCache.get(p) for p in self.game.players if GameFlowCache.get(p).is_current_player][0]

    def start_player(self):
        """
        Handles getting the current player in a way that is consistant with the caching in GameFlowCache
        """
        return [GameFlowCache.get(p) for p in self.game.players if GameFlowCache.get(p).is_start_player][0]


